#include<stdio.h>
#include<winsock2.h>
#include <pthread.h>

void *connection_handler(void *);

typedef struct __sock_client
{
	struct sockaddr_in 	addr;
	int 				fd;
	char 				ss_addr[32];	//***.***.***.***:xxx
}sockclt;

int main(int argc , char *argv[])
{
    WSADATA wsa;			//Windows Sockets API  Data Structure
    SOCKET s , new_socket;

    struct sockaddr_in server;
    struct __sock_client client;
    
    int c;
    char *message,server_reply[2000];

    printf("\nInitialising Winsock...");
    if (WSAStartup(MAKEWORD(2,2),&wsa) != 0)
    {
        printf("Failed. Error Code : %d",WSAGetLastError());
        return 1;
    }

    printf("Initialised.\n");

    //Create a socket
    if((s = socket(AF_INET , SOCK_STREAM , 0 )) == INVALID_SOCKET)
    {
        printf("Could not create socket : %d" , WSAGetLastError());
    }

    printf("Socket created.\n");

    //Prepare the sockaddr_in structure
    server.sin_family = AF_INET;
    server.sin_addr.s_addr = INADDR_ANY;
    int PORT;
    printf("Socket Server open Port: ");
    scanf("%d", &PORT);
    server.sin_port = htons( PORT );

    //Bind
    if( bind(s ,(struct sockaddr *)&server , sizeof(server)) == SOCKET_ERROR)
    {
        printf("Bind failed with error code : %d" , WSAGetLastError());
    }

    puts("Bind done");

    //Listen to incoming connections
    listen(s , 3);

    //Accept and incoming connection
    puts("Waiting for incoming connections...");

    c = sizeof(struct sockaddr_in);
    pthread_t thread_id;
    while( 1 )
    {
    	client.fd = accept(s, (struct sockaddr *)&client.addr, &c);
	    if(client.fd == INVALID_SOCKET)
	    {
	        printf("accept failed with error code : %d" , WSAGetLastError());
	    }
		else
	    {
			sprintf(client.ss_addr, "%s:%d", inet_ntoa(client.addr.sin_addr), ntohs(client.addr.sin_port));
			printf("New connection %s\n", client.ss_addr);
		}

        if( pthread_create( &thread_id , NULL ,  connection_handler , (void*)&client) < 0)
        {
            perror("could not create thread");
            return 1;
        }
         
        //Now join the thread , so that we dont terminate before the thread
        //pthread_join( thread_id , NULL);
        //puts("Handler assigned");
    }
     
    if (new_socket < 0)
    {
        perror("accept failed");
        return 1;
	}

    closesocket(s);
    WSACleanup();

    return 0;
}

void *connection_handler(void *socket_desc)
{
    //Get the socket descriptor
    struct __sock_client* client = (struct __sock_client*)socket_desc;
    int read_size;
    char *message,client_message[2000];
     
    //Send some messages to the client
    message = "Greetings! I am your connection handler";
    send(client->fd , message , strlen(message) , 0);
    
    message = "Now type something and i shall repeat what you type ";
    send(client->fd , message , strlen(message) , 0);
    
    while(1)
    {
	    //Receive a reply from the server
	    if((read_size = recv(client->fd , client_message , 2000 , 0)) == SOCKET_ERROR)
	    {
	        puts("recv failed");
	    }
		if(strncmp(client_message, ".CLNTEXIT", 9) == 0)
		{
			printf("Client[%s] handler is exit.", client->ss_addr);
			//goto EXIT_HANDLER;
			break;
		}
	    //Add a NULL terminating character to make it a proper string before printing
	    client_message[read_size] = '\0';
	    printf("%s /> %s\n", client->ss_addr, client_message);
	    //Reply to client
	    send(client->fd, client_message, read_size, 0);
	}
	
    return (void*)0;
} 